package schemax

import (
	"errors"
	"gitee.com/zhongguo168a/gocodes/datax/schemax/basickind"
	"gitee.com/zhongguo168a/gocodes/datax/schemax/fieldkind"
	"reflect"
)

func CreateDecl(st reflect.Type) IDecl {
	decl := ParseClass(st)
	AddDecl(decl)

	if st.Kind() == reflect.Ptr {
		st = st.Elem()
	}
	for i := 0; i < st.NumField(); i++ {
		field := st.Field(i)
		ftyp := field.Type
		if ftyp.Kind() == reflect.Ptr {
			ftyp = ftyp.Elem()
		}
		if ftyp.Kind() == reflect.Struct {
			CreateDecl(ftyp)
		}
	}

	return decl
}

// golang不支持枚举类型，无法在运行时解析
// 如需枚举需求，可通过注解工具创建枚举代码
func ParseEnum(val interface{}) *EnumDecl {
	return nil
}

func ParseClass(rtyp reflect.Type) *ClassDecl {
	return parseClass(rtyp)
}

func parseClass(rtyp reflect.Type) *ClassDecl {
	if rtyp.Kind() == reflect.Ptr {
		rtyp = rtyp.Elem()
	}
	decl := &ClassDecl{
		Name: rtyp.String(),
		Parent: func() string {
			for i := 0; i < rtyp.NumField(); i++ {
				ftyp := rtyp.Field(i)
				if ftyp.Anonymous {
					return ftyp.Type.String()
				}
			}
			return ""

		}(),
		Fields: func() (x []*Field) {
			for i := 0; i < rtyp.NumField(); i++ {
				field := rtyp.Field(i)
				ftyp := field.Type
				if field.Anonymous {
					continue
				}
				f := &Field{
					Name:     field.Name,
					Type:     parseFieldType(ftyp),
					Value:    "",
					Comments: nil,
					Tags:     nil,
					//Unsafe: UnsafeInfo{
					//	Offset: field.Offset,
					//	Kind:   ftyp.Kind(),
					//},
				}
				x = append(x, f)
			}
			return

		}(),
		Comments: nil,
		Tags:     nil,
	}

	return decl
}

func parseFieldType(ftyp reflect.Type) (r IType) {
	switch ftyp.Kind() {
	case reflect.Ptr:
		ftyp = ftyp.Elem()
		switch fieldkind.ReflectToFieldKind(ftyp) {
		case fieldkind.Class:
		default:
			panic(errors.New("not support field type [kind" + ftyp.String() + "]"))
		}
	default:
	}

	switch fieldkind.ReflectToFieldKind(ftyp) {
	case fieldkind.Class:
		r = &ClassType{
			Decl: ftyp.String(),
		}
	case fieldkind.Map:
		r = &MapType{
			Key:   parseFieldType(ftyp.Key()),
			Value: parseFieldType(ftyp.Elem()),
		}
	case fieldkind.Array:
		r = &ArrayType{
			Elem: parseFieldType(ftyp.Elem()),
		}
	case fieldkind.Enum:
		r = &EnumType{
			Decl: ftyp.String(),
		}
	case fieldkind.Basic:
		r = &BasicType{
			Kind: basickind.ReflectKindToBasicKind(ftyp.Kind()),
		}
	case fieldkind.Any:
		r = &AnyType{}
	default:
		panic(errors.New("not support field type [kind" + ftyp.String() + "]"))
	}

	return
}
